package com.codeborne.selenide.commands;

import com.codeborne.selenide.Command;
import com.codeborne.selenide.Driver;
import com.codeborne.selenide.SelenideElement;
import com.codeborne.selenide.impl.WebElementSource;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;

/**
 * Clean the input field value.
 * <br>
 * <p>
 *  The standard Selenium method {@link WebElement#clear()} does not help in case of
 *  "tricky" inputs generated by Vue.js, React and other fancy frameworks.
 * </p>
 * <br>
 * <p>
 *  That's why we need to clear the field value by emulating real user actions:
 * </p>
 * <ol>
 *   <li>Select the whole text</li>
 *   <li>press "Backspace"</li>
 * </ol>
 */
@ParametersAreNonnullByDefault
public class Clear implements Command<SelenideElement> {
  private static final Logger log = LoggerFactory.getLogger(Clear.class);

  @Nonnull
  @CheckReturnValue
  @Override
  public SelenideElement execute(SelenideElement proxy, WebElementSource locator, @Nullable Object[] args) {
    WebElement input = locator.findAndAssertElementIsEditable();
    clearAndTrigger(locator.driver(), input);
    return proxy;
  }

  /**
   * Clear the input content and trigger "change" and "blur" events
   *
   * <p>
   * This is the shortest keys combination I found in May 2022.<br>
   * It seems to work in Firefox, Chrome on Mac and on Linux smoothly.
   * </p>
   */
  protected void clearAndTrigger(Driver driver, WebElement input) {
    clear(driver, input);
    blurSafely(driver, input);
  }

  protected void blurSafely(Driver driver, WebElement input) {
    try {
      driver.executeJavaScript("arguments[0].blur()", input);
    }
    catch (StaleElementReferenceException elementHasDisappeared) {
      log.debug("The input has disappeared after clearing: {}", elementHasDisappeared.toString());
    }
  }

  /**
   * Clear the input content without triggering "change" and "blur" events
   */
  public void clear(Driver driver, WebElement input) {
    input.clear();
  }
}
